/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.appspot.trick.it.admin.api;

import com.appspot.trick.it.admin.Constants;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Files.Insert;
import com.google.api.services.drive.model.About;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.ParentReference;
import eu.medsea.mimeutil.MimeType;
import eu.medsea.mimeutil.MimeUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 *
 * @author takahara
 */
public class DriveAPIService {

    private final Drive drive;

    /**
     * コンストラクタ
     *
     * @throws java.lang.Exception
     */
    public DriveAPIService() throws Exception {

        GoogleOauthAPIService googleOauthAPIService = new GoogleOauthAPIService();
        Credential credential = googleOauthAPIService.getCredentials();

        HttpTransport httpTransport = new NetHttpTransport();
        JacksonFactory jsonFactory = new JacksonFactory();

        drive = new Drive.Builder(httpTransport, jsonFactory, credential)
                .setApplicationName(Constants.APPLICATION_NAME)
                .build();
    }

    /**
     * About 情報の取得
     *
     * @return
     * @throws IOException
     */
    public About getAbout() throws IOException {
        return drive.about().get().execute();
    }

    /**
     * Root Folder ID を取得
     *
     * @return
     * @throws IOException
     */
    public String getRootFolderId() throws IOException {
        return getAbout().getRootFolderId();
    }

    /**
     * 指定フォルダの子リストを取得
     *
     * @param folderId
     * @return
     * @throws IOException
     */
    public List<File> getChildrenFoldersList(String folderId) throws IOException {
        return drive.files().list().setQ("'" + folderId + "' in parents"
                + " and mimeType = '" + Constants.GOOGLE_FILE_TYPES_ENUM.folder.getMineType() + "' and trashed=false")
                .execute().getItems();
    }

    /**
     * 指定フォルダの子リストを取得
     *
     * @param folderId
     * @return
     * @throws IOException
     */
    public List<File> getChildrenFilesList(String folderId) throws IOException {
        return drive.files().list().setQ("'" + folderId + "' in parents and trashed=false").execute().getItems();
    }

    /**
     * 指定フォルダの特定の名前の子ファイルリストを取得
     *
     * @param folderId
     * @param fileTitle
     * @return
     * @throws IOException
     */
    public List<File> getChildrenFolderList(String folderId, String fileTitle) throws IOException {
        return drive.files().list().setQ("'" + folderId + "' in parents"
                + " and mimeType = '" + Constants.GOOGLE_FILE_TYPES_ENUM.folder.getMineType() + "'"
                + " and trashed=false"
                + " and title = '" + fileTitle + "'")
                .execute().getItems();
    }

    /**
     * 指定フォルダの特定の名前の子ファイルリストを取得
     *
     * @param folderId
     * @param fileTitle
     * @return
     * @throws IOException
     */
    public List<File> getChildrenFilesListByTitle(String folderId, String fileTitle) throws IOException {
        return drive.files().list().setQ("'" + folderId + "' in parents"
                + " and mimeType != '" + Constants.GOOGLE_FILE_TYPES_ENUM.folder.getMineType() + "'"
                + " and trashed=false"
                + " and title = '" + fileTitle + "'")
                .execute().getItems();
    }

    /**
     * 指定フォルダの特定のタイプの子ファイルリストを取得
     *
     * @param folderId
     * @param mimeType
     * @return
     * @throws IOException
     */
    public List<File> getChildrenFilesListByMineType(String folderId, String mimeType) throws IOException {
        return drive.files().list().setQ("'" + folderId + "' in parents"
                + " and mimeType != '" + Constants.GOOGLE_FILE_TYPES_ENUM.folder.getMineType() + "'"
                + " and trashed=false"
                + " and mimeType = '" + mimeType + "'")
                .execute().getItems();
    }

    /**
     * ファイル検索
     *
     * @param searchString
     * @return
     * @throws IOException
     */
    public List<File> searchFileList(String searchString) throws IOException {
        return drive.files().list().setQ("title contains '" + searchString + "' and trashed=false")
                .execute().getItems();
    }

    /**
     * ゴミ箱内のファイルを取得
     *
     * @return
     * @throws IOException
     */
    public List<File> getTrashFilesList() throws IOException {
        return drive.files().list().setQ("trashed=true")
                .execute().getItems();
    }

    /**
     * 共有されているファイルリストを取得
     *
     * @return
     * @throws IOException
     */
    public List<File> getSharedWithMeFilesList() throws IOException {
        return drive.files().list().setQ("sharedWithMe and trashed=false")
                .execute().getItems();
    }

    /**
     * ファイルの取得
     *
     * @param fileId
     * @return
     * @throws IOException
     */
    public File getFile(String fileId) throws IOException {
        return drive.files().get(fileId).execute();
    }

    /**
     * ファイル内容の変更
     *
     * @param fileId
     * @param file
     * @throws IOException
     */
    public void updateFile(String fileId, File file) throws IOException {
        drive.files().update(fileId, file).execute();
    }

    /**
     * ファイル削除
     *
     * @param file
     * @throws IOException
     */
    public void deleteFile(File file) throws IOException {

        if (file.getExplicitlyTrashed() != null && file.getExplicitlyTrashed()) {
            System.out.println("delete");
            drive.files().delete(file.getId()).execute();
        } else {
            System.out.println("trash");
            drive.files().trash(file.getId()).execute();
        }
    }
    
    /**
     * ファイルをゴミ箱に入れる
     * @param file
     * @throws IOException 
     */
    public void trashFile(File file) throws IOException {
        drive.files().trash(file.getId()).execute();
    }

    /**
     * ゴミ箱にあるファイルを復元
     *
     * @param file
     * @throws IOException
     */
    public void untrashFile(File file) throws IOException {
        drive.files().untrash(file.getId()).execute();
    }

    /**
     * フォルダ追加
     *
     * @param parentId
     * @param title
     * @return
     */
    public File insertFolder(String parentId, String title) {
        File body = new File();
        body.setTitle(title);
        body.setMimeType(Constants.GOOGLE_FILE_TYPES_ENUM.folder.getMineType());

        if (parentId != null && parentId.length() > 0) {
            body.setParents(
                    Arrays.asList(new ParentReference().setId(parentId)));
        }

        try {
            File file = drive.files().insert(body).execute();

            // Uncomment the following line to print the File ID.
            // System.out.println("File ID: %s" + file.getId());
            return file;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * フォルダ追加
     *
     * @param parentId
     * @param mimeType
     * @param title
     * @return
     */
    public File insertFile(String parentId, String mimeType, String title) {
        File body = new File();
        body.setTitle(title);
        body.setMimeType(mimeType);

        if (parentId != null && parentId.length() > 0) {
            body.setParents(
                    Arrays.asList(new ParentReference().setId(parentId)));
        }

        try {
            File file = drive.files().insert(body).execute();

            // Uncomment the following line to print the File ID.
            // System.out.println("File ID: %s" + file.getId());
            return file;
        } catch (IOException e) {
            return null;
        }
    }

    /**
     * ファイルアップデート
     *
     * @param parentId
     * @param file
     * @return
     * @throws java.io.IOException
     */
    public File uploadFile(String parentId, java.io.File file) throws IOException {

        String mimeType;
        String[] tmp = file.getName().split("\\.");

        if (Constants.GOOGLE_FILE_UNIQUE_MIME_TYPE.containsKey(tmp[1])) {
            mimeType = Constants.GOOGLE_FILE_UNIQUE_MIME_TYPE.get(tmp[1]);
        } else {
            // MimeUtilを使ってファイル種類判断
            MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
            Collection<String> mimeTypes = MimeUtil.getMimeTypes(file);
            mimeType = mimeTypes.toArray(new MimeType[mimeTypes.size()])[0].toString();
        }

        File body = new File();
        body.setTitle(file.getName());
        body.setParents(
                Arrays.asList(new ParentReference().setId(parentId)));
        body.setMimeType(mimeType);

        FileContent mediaContent = new FileContent(mimeType, file);
        System.out.println(mimeType);

        return drive.files().insert(body, mediaContent).execute();
    }

    /**
     * ファイルアップデート
     *
     * @param parentId
     * @param file
     * @return
     * @throws java.io.IOException
     */
    public Insert getFileInsert(String parentId, java.io.File file) throws IOException {

        String mimeType;
        String[] tmp = file.getName().split("\\.");

        if (Constants.GOOGLE_FILE_UNIQUE_MIME_TYPE.containsKey(tmp[1])) {
            mimeType = Constants.GOOGLE_FILE_UNIQUE_MIME_TYPE.get(tmp[1]);
        } else {
            // MimeUtilを使ってファイル種類判断
            MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
            Collection<String> mimeTypes = MimeUtil.getMimeTypes(file);
            mimeType = mimeTypes.toArray(new MimeType[mimeTypes.size()])[0].toString();
        }

        File body = new File();
        body.setTitle(file.getName());
        body.setParents(
                Arrays.asList(new ParentReference().setId(parentId)));
        body.setMimeType(mimeType);

        FileContent mediaContent = new FileContent(mimeType, file);
        mediaContent.setType(mimeType);
        System.out.println(mimeType);

        return drive.files().insert(body, mediaContent);
    }

    /**
     * ファイルアップデート
     *
     * @param parentId
     * @param file
     * @param fileTitle
     * @return
     * @throws java.io.IOException
     */
    public Insert getFileInsert(String parentId, java.io.File file, String fileTitle) throws IOException {

        String mimeType;
        String[] tmp = file.getName().split("\\.");

        if (Constants.GOOGLE_FILE_UNIQUE_MIME_TYPE.containsKey(tmp[1])) {
            mimeType = Constants.GOOGLE_FILE_UNIQUE_MIME_TYPE.get(tmp[1]);
        } else {
            // MimeUtilを使ってファイル種類判断
            MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
            Collection<String> mimeTypes = MimeUtil.getMimeTypes(file);
            mimeType = mimeTypes.toArray(new MimeType[mimeTypes.size()])[0].toString();
        }

        File body = new File();
        body.setTitle(fileTitle);
        body.setParents(
                Arrays.asList(new ParentReference().setId(parentId)));
        body.setMimeType(mimeType);

        FileContent mediaContent = new FileContent(mimeType, file);
        System.out.println(mimeType);

        return drive.files().insert(body, mediaContent);
    }
    
    /**
     * ファイルの中身を差し替える
     * @param file
     * @param newFile
     * @throws IOException 
     */
    public void updateFile(File file, java.io.File newFile) throws IOException {
        FileContent mediaContent = new FileContent(file.getMimeType(), newFile);
        drive.files().update(file.getId(), file, mediaContent).execute();
    }

    /**
     * ファイルの複製
     *
     * @param file
     * @return
     * @throws IOException
     */
    public File makeCopy(File file) throws IOException {
        File copiedFile = new File();
        copiedFile.setTitle(file.getTitle() + " - コピー");
        return drive.files().copy(file.getId(), copiedFile).execute();
    }

    /**
     * ファイルの移動
     *
     * @param targetFileId
     * @param targetParentId
     * @throws IOException
     */
    public void moveFile(String targetFileId, String targetParentId) throws IOException {
        File targetFile = getFile(targetFileId);
        targetFile.setParents(
                Arrays.asList(new ParentReference().setId(targetParentId)));

        updateFile(targetFileId, targetFile);
    }

    /**
     * ダウンロードファイルのInputStreamを取得
     *
     * @param file
     * @return
     * @throws IOException
     */
    public InputStream downloadFile(File file) throws IOException {
        if (file.getDownloadUrl() != null && file.getDownloadUrl().length() > 0) {
            HttpResponse resp = drive.getRequestFactory().buildGetRequest(new GenericUrl(file.getDownloadUrl())).execute();
            return resp.getContent();
        } else {
            // The file doesn't have any content stored on Drive.
            return null;
        }
    }
    
    public String getDocumentAsHtml(File file) throws IOException {
        if (file.getDownloadUrl() != null && file.getDownloadUrl().length() > 0) {
            HttpResponse resp = drive.getRequestFactory().buildGetRequest(new GenericUrl(file.getExportLinks().get("text/html"))).execute();
            
            InputStream inputStream = resp.getContent();

            BufferedReader reader
                    = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            StringBuilder sb = new StringBuilder();
            String line;
            while (null != (line = reader.readLine())) {
                sb.append(line);
            }
            return sb.toString();
            
        } else {
            // The file doesn't have any content stored on Drive.
            return null;
        }
    }

}
